package com.glsc.ngateway.platform.utils.file;

import com.glsc.ngateway.platform.utils.AssertOverride;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.Assert;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Weiziteng on 2022/4/22.
 */
@Slf4j
public class ExcelUtil {

    private int rowOffset = 4;
    private int columnsOffset = 0;
    private String filePostfix = ".xlsx";
    private static String outputFilePath = "/tmp/amfile/";

    List<CellStyle> cellStyles;
    List<CellStyle> addCellStyles;
    CellStyle defaultCellStyle;
    CellStyle addCellStyle;

    public ExcelUtil() {
        init();
    }

    private void init() {
        cellStyles = new ArrayList<>();
        addCellStyles = new ArrayList<>();
    }

    protected void buildParamter(ExcelNameEnum excelNameEn) {
        rowOffset = excelNameEn.getBeginRow();
        columnsOffset = excelNameEn.getBeginCol();
    }

    /**
     * 生成Excel文件流
     * @param datas 数据
     * @param template 模板
     * @return 字节数组
     */
    public byte[] buildExcelFileByte(List<List<String>> datas, String template, int sheetNum) {
        AssertOverride.notNull(template, "template name must not be null");
        if (datas == null) {
            datas = new ArrayList<>();
        }
        try (
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            InputStream inputStream = this.getClass().getResourceAsStream("/exceltemplates/" + template)) {

            Workbook wb = new XSSFWorkbook(inputStream);
            Sheet sheet = wb.getSheetAt(sheetNum);
            int lastRow = sheet.getLastRowNum();
            if (lastRow <= rowOffset) {
                defaultCellStyle = wb.createCellStyle();
                defaultCellStype(defaultCellStyle);
                defaultCellStyle.setDataFormat(wb.createDataFormat().getFormat("@"));
            }
            wb.setActiveSheet(sheetNum);
            for (int i = 0; i < datas.size(); i++) {
                createExcelRow(datas.get(i), i, sheet);
            }
            wb.write(outputStream);
            return outputStream.toByteArray();
        } catch (FileNotFoundException e) {
            log.error("生成临时文件未找到异常！", e);
            throw new RuntimeException("生成临时文件未找到异常", e);
        } catch (IOException e) {
            log.error("生成临时文件IO异常！", e);
            throw new RuntimeException("生成临时文件IO异常", e);
        }
    }

    public static byte[] convertWbToByte(Workbook wb){
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            wb.write(outputStream);
            return outputStream.toByteArray();
        } catch (Exception e) {
            log.error("生成文件异常！", e);
            throw new RuntimeException("生成文件异常", e);
        }
    }


    /**
     * 生成Excel文件流
     * @param datas 数据
     * @param template 模板
     * @return 字节数组
     */
    public Workbook buildExcelWorkBook(List<List<String>> datas, String template, int sheetNum) {
        AssertOverride.notNull(template, "template name must not be null");
        if (datas == null) {
            datas = new ArrayList<>();
        }
        try (
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            InputStream inputStream = this.getClass().getResourceAsStream("/exceltemplates/" + template)) {

            Workbook wb = new XSSFWorkbook(inputStream);
            Sheet sheet = wb.getSheetAt(sheetNum);
            int lastRow = sheet.getLastRowNum();
            if (lastRow <= rowOffset) {
                defaultCellStyle = wb.createCellStyle();
                defaultCellStype(defaultCellStyle);
                defaultCellStyle.setDataFormat(wb.createDataFormat().getFormat("@"));
            }
            wb.setActiveSheet(sheetNum);
            for (int i = 0; i < datas.size(); i++) {
                createExcelRow(datas.get(i), i, sheet);
            }
            return wb;
        } catch (FileNotFoundException e) {
            log.error("生成临时文件未找到异常！", e);
            throw new RuntimeException("生成临时文件未找到异常", e);
        } catch (IOException e) {
            log.error("生成临时文件IO异常！", e);
            throw new RuntimeException("生成临时文件IO异常", e);
        }
    }

    /**
     * 根据List数据填充单元行
     * @param data 数据
     * @param sheet 页
     */
    private void createExcelRow(List<String> data, int rows, Sheet sheet) {
        Row row;
        if (rows == 0) {
            row = sheet.getRow(rows + rowOffset);
            if (row == null) {
                row = sheet.createRow(rows + rowOffset);
            }
            setCellTypleInit(data.size(), row);
        } else {
            row = sheet.createRow(rows + rowOffset);
        }
        // 序号列特殊处理
        for (int i = 0; i < data.size(); i++) {
            Cell cell = row.createCell(i + columnsOffset);
            cell.setCellStyle(cellStyles.get(i));
            cell.setCellValue(data.get(i));
        }
    }

    private void setCellTypleInit(int lenght, Row row) {
        for (int i = 0; i < lenght; i++) {
            Cell cell = row.getCell(i);
            if (cell != null) {
                cellStyles.add(cell.getCellStyle());
            } else {
                cellStyles.add(defaultCellStyle);
            }
        }
    }

    private void setCellTypleInitForAdd(int lenght, Row row) {
        for (int i = 0; i < lenght; i++) {
            Cell cell = row.getCell(i+rowOffset);
            if (cell != null) {
                addCellStyles.add(cell.getCellStyle());
            } else {
                addCellStyles.add(addCellStyle);
            }
        }
    }

    private void defaultCellStype(CellStyle cellStyle) {
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
    }

    public Workbook addExcelData(Workbook wb, List<List<String>> datas) {
        if (datas == null) {
            datas = new ArrayList<>();
        }
        try {
            Sheet sheet = wb.getSheetAt(0);
            int lastRow = sheet.getLastRowNum();
            addCellStyle = wb.createCellStyle();
            addCellStype(addCellStyle);
            rowOffset = lastRow;
            wb.setActiveSheet(0);
            for (int i = 0; i < datas.size(); i++) {
                createExcelRowForAdd(datas.get(i), i, sheet);
            }
        } catch (Exception e) {
            log.error("追加数据生成Excel异常！", e);
            throw new RuntimeException("追加数据生成Excel异常", e);
        }
        return wb;
    }

    private void addCellStype(CellStyle cellStyle) {
        addCellStyle.setAlignment(HorizontalAlignment.CENTER);
        addCellStyle.setBorderBottom(BorderStyle.THIN);
        addCellStyle.setBorderLeft(BorderStyle.THIN);
        addCellStyle.setBorderTop(BorderStyle.THIN);
        addCellStyle.setBorderRight(BorderStyle.THIN);
        Font titleFont = new XSSFFont();
//        titleFont.setBold(true);
        titleFont.setFontHeightInPoints((short) 11);
        titleFont.setFontName("宋体");
        addCellStyle.setFont(titleFont);
    }

    /**
     * excel后续添加内容
     *
     * @param data
     * @param rows
     * @param sheet
     */
    private void createExcelRowForAdd(List<String> data, int rows, Sheet sheet) {
        Row row;
        if (rows == 0) {
            row = sheet.getRow(rows + rowOffset);
            setCellTypleInitForAdd(data.size(), row);
            row = sheet.createRow(rows + rowOffset + 1);
        } else {
            row = sheet.createRow(rows + rowOffset + 1);
        }
        // 序号列特殊处理
        for (int i = 0; i < data.size(); i++) {
            Cell cell = row.createCell(i + columnsOffset);
            cell.setCellStyle(addCellStyles.get(0));
            cell.setCellValue(data.get(i));
        }
    }

    public byte[] convertToBytes(Workbook wb) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            wb.write(outputStream);
            return outputStream.toByteArray();
        } catch (FileNotFoundException e) {
            log.error("生成临时文件未找到异常！", e);
            throw new RuntimeException("生成临时文件未找到异常", e);
        } catch (IOException e) {
            log.error("生成临时文件IO异常！", e);
            throw new RuntimeException("生成临时文件IO异常", e);
        }
    }
}
